﻿using Sidvall.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Sidvall.Security
{
    public class ResourceItem
    {
        #region Public Members

        #region Resource

        private string _Resource = string.Empty;
        public string Resource
        {
            get
            {
                return _Resource;
            }
            set
            {
                value = Sidvall.Business.ValidationManager.GetValidString(value, false, null);
                _Resource = value;
                if (string.IsNullOrWhiteSpace(_Resource))
                {
                    this.ResourceItemId = null;
                    this.Action = null;
                }
            }
        }

        #endregion
        #region ResourceItemId

        private string _ResourceItemId = string.Empty;
        public string ResourceItemId
        {
            get
            {
                return _ResourceItemId;
            }
            set
            {
                value = Sidvall.Business.ValidationManager.GetValidString(value, false, null);
                _ResourceItemId = value;
            }
        }

        #endregion
        #region Action

        private string _Action = string.Empty;
        public string Action
        {
            get
            {
                return _Action;
            }
            set
            {
                value = Sidvall.Business.ValidationManager.GetValidString(value, false, null);
                _Action = value;
                if (string.IsNullOrWhiteSpace(_Action))
                    this.SubAction = null;
            }
        }

        #endregion
        #region SubAction

        private string _SubAction = string.Empty;
        public string SubAction
        {
            get
            {
                return _SubAction;
            }
            set
            {
                value = Sidvall.Business.ValidationManager.GetValidString(value, false, null);
                _SubAction = value;
            }
        }

        #endregion
        #region Description

        private string _Description = string.Empty;
        public string Description
        {
            get
            {
                return _Description;
            }
            set
            {
                value = Sidvall.Business.ValidationManager.GetValidString(value, false, null);
                _Description = value;
            }
        }

        #endregion
        #region AccessLevel

        private ResourceItemAccessLevel _AccessLevel = ResourceItemAccessLevel.Unknown;
        public ResourceItemAccessLevel AccessLevel
        {
            get
            {
                return _AccessLevel;
            }
            set
            {
                _AccessLevel = value;
            }
        }

        #endregion

        #region GetKey

        public string GetKey()
        {
            return GetKey(this);
        }

        #endregion
        #region ToString

        public override string ToString()
        {
            return GetKey();
        }

        #endregion

        #region CreateResourceItem

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        public static ResourceItem CreateResourceItem(IEnumerable<ResourceItem> items, ResourceItemAccessLevel defaultAccessLevel, string descriptionSeparator,
            bool includeSubActionsInDescription)
        {
            if ((items == null) || (!items.Any()))
            {
                return new ResourceItem()
                {
                    AccessLevel = defaultAccessLevel,
                };
            }
            var resources = (from o in items
                             where !string.IsNullOrWhiteSpace(o.Resource)
                             select o.Resource).Distinct().ToList();
            var actions = (from o in items
                           where !string.IsNullOrWhiteSpace(o.Action)
                           select o.Action).Distinct().ToList();
            var subActions = (from o in items
                              where !string.IsNullOrWhiteSpace(o.SubAction)
                              select o.SubAction).Distinct().ToList();
            var newDescriptions = new List<string>();
            var accessLevel = ResourceItemAccessLevel.None;
            foreach (var item in items)
            {
                var descriptionRow = string.Empty;
                if ((resources.Count > 1) && (!string.IsNullOrWhiteSpace(item.Resource)))
                {
                    if (!string.IsNullOrWhiteSpace(descriptionRow))
                        descriptionRow += Separator;
                    descriptionRow += item.Resource;
                }
                if ((actions.Count > 1) && (!string.IsNullOrWhiteSpace(item.Action)))
                {
                    if (!string.IsNullOrWhiteSpace(descriptionRow))
                        descriptionRow += Separator;
                    descriptionRow += item.Action;
                }
                if (((includeSubActionsInDescription) || (subActions.Count > 1)) && (!string.IsNullOrWhiteSpace(item.SubAction)))
                {
                    if (!string.IsNullOrWhiteSpace(descriptionRow))
                        descriptionRow += Separator;
                    descriptionRow += item.SubAction;
                }
                if (!string.IsNullOrWhiteSpace(item.Description))
                {
                    if (!string.IsNullOrWhiteSpace(descriptionRow))
                        descriptionRow += ": ";
                    descriptionRow += item.Description;
                }
                switch (item.AccessLevel)
                {
                    case ResourceItemAccessLevel.Public:
                        accessLevel = ResourceItemAccessLevel.Public;
                        break;
                    case ResourceItemAccessLevel.Protected:
                        if (accessLevel == ResourceItemAccessLevel.None)
                            accessLevel = ResourceItemAccessLevel.Protected;
                        break;
                    default:
                        break;
                }
                if ((!string.IsNullOrWhiteSpace(descriptionRow)) && (!newDescriptions.Contains(descriptionRow)))
                    newDescriptions.Add(descriptionRow);
            }
            return new ResourceItem()
            {
                Resource = resources.JoinToString(", "),
                Action = actions.JoinToString(", "),
                SubAction = subActions.JoinToString(", "),
                Description = newDescriptions.JoinToString(descriptionSeparator),
                AccessLevel = accessLevel,
            };
        }

        #endregion
        #region GetKey

        public static string GetKey(ResourceItem item)
        {
            if (item == null)
                throw new System.ArgumentNullException("item");
            var sb = new System.Text.StringBuilder();
            if (!string.IsNullOrWhiteSpace(item.Resource))
            {
                sb.Append(item.Resource);
                if (!string.IsNullOrWhiteSpace(item.ResourceItemId))
                    sb.Append(ResourceItemSeparator + item.ResourceItemId);
                if (!string.IsNullOrWhiteSpace(item.Action))
                {
                    sb.Append(Separator + item.Action);
                    if (!string.IsNullOrWhiteSpace(item.SubAction))
                        sb.Append(Separator + item.SubAction);
                }
            }
            return sb.ToString();
        }

        #endregion

        #endregion
        #region Private Members

        private const string Separator = ".";
        private const string ResourceItemSeparator = "|";

        #endregion
        #region Constructors

        public ResourceItem()
        {
        }

        #endregion
    }
}
